package example.players;

/**
 * Created by Leo on 08/04/14.
 */

import roshambo.Player;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Random;

public class DoubleMemento implements Player {
    private int memory = 3;
    private int numGames;
    private int score[];
    private int lastMove;

    private ArrayList<String> mtuples;      //all possible move sequences of length 3
    private Hashtable<String,int[]> data;   //holds how many times the opponent played a hand given a previous sequence of moves
    private String myMoves;
    private String opMoves;

    private Random rand;

    //constructor
    public DoubleMemento(int memory) {
        this.memory = memory;
    }

    @Override
    public int play() {
        if(myMoves.length() < memory) {
            lastMove = rand.nextInt(3)+1;
            return lastMove;
        }

        double u = rand.nextDouble();
        double[] p = computeProbabilities();
        if(u < p[0] /*op will play rock*/) {
            lastMove = PAPEL;
            return lastMove;
        }
        if(u < p[0]+p[1] /*op will play paper*/) {
            lastMove = TESOURA;
            return lastMove;
        }
        lastMove = PEDRA;
        return lastMove;
    }

    @Override
    public void receive(int result) {
        int winner = whoWon(lastMove,result);
        score[winner] += 1;

        myMoves += moveToString(lastMove);
        opMoves += moveToString(result);

        if(opMoves.length() > memory){
            String myNewData = myMoves.substring(opMoves.length() - memory - 1, opMoves.length() - 1);
            String opNewData = opMoves.substring(opMoves.length() - memory - 1, opMoves.length() - 1);
            data.get(myNewData + opNewData)[result-1]++;
        }
    }

    @Override
    public void newGame(int games) {
        numGames = games;
        rand = new Random();

        //initializing data set structures
        ArrayList<String> last = new ArrayList<String>();   //used to create all move sequences of length 3
        last.add("r");
        last.add("p");
        last.add("s");

        for(int i = 0; i < memory-1; i++) {
            ArrayList<String> nw = new ArrayList<String>();
            for(int j = 0; j < last.size(); j++) nw.add("r" + last.get(j));
            for(int j = 0; j < last.size(); j++) nw.add("p" + last.get(j));
            for(int j = 0; j < last.size(); j++) nw.add("s" + last.get(j));

            last = nw ;
        }

        mtuples = new ArrayList<String>();
        for(int i = 0; i < last.size(); i++) {
            mtuples.add(last.get(i));
        }

        data = new Hashtable<String,int[]>();
        for(int i = 0; i < mtuples.size(); i++) {
            for(int j = 0; j < mtuples.size(); j++){
                int[] init = {1,1,1};
                data.put(mtuples.get(i) + mtuples.get(j), init);
            }

        }
        //end of data set structures

        //initializing move histories
        myMoves = "";
        opMoves = "";

        //initializing scores
        score = new int[3];
        score[0] = 0;   //my score
        score[1] = 0;   //op score
        score[2] = 0;   //draw
    }

    public String moveToString(int i) {
        if(i == PEDRA) return "r";
        if(i == PAPEL) return "p";
        if(i == TESOURA) return "s";
        return "";
    }

    public int whoWon(int me, int op) {
        if(me == op) return 2;

        if( me == PEDRA ){
            if( op == PAPEL ) return 1;
            else return 0;
        }

        if( me == PAPEL ){
            if( op == TESOURA ) return 1;
            else return 0;
        }

        if( me == TESOURA ){
            if( op == PEDRA ) return 1;
            else return 0;
        }

        return 10;
    }

    public double[] computeProbabilities() {
        double[] prob = {1.0,1.0,1.0};
        if(opMoves.length() < memory) {
            prob[0] = 1.0/3;
            prob[1] = 1.0/3;
            prob[2] = 1.0/3;
            return prob;
        }

        String myRecentData = myMoves.substring(opMoves.length() - memory, opMoves.length());
        String opRecentData = opMoves.substring(opMoves.length() - memory, opMoves.length());
        int[] d = data.get(myRecentData+opRecentData);
        int n = 0;
        for(int i = 0; i < d.length; i++){
            n += d[i];
        }

        for(int i = 0; i < prob.length; i++){
            prob[i] = ((double)d[i])/((double)n);
        }

        return prob;
    }
}
